gulp 自动化生成雪碧图并压缩


参考:
雪碧图生产: https://github.com/twolfson/gulp.spritesmith

图片压缩: https://github.com/sindresorhus/gulp-imagemin


之前只是听说构建工具可以干这个活,不需要我们再去制作出雪碧图,但在项目中没有用过,然后这两天看了一下前辈在用,挺好奇就尝试了一下,参考了一下前人的意见,决定选用的是 gulp.spritesmith,图片压缩选用的是 gulp-imagemin ,这个插件能够帮我们压缩 PNG, JPEG, GIF 以及 SVG 文件。

1.创建项目、安装依赖
packge.json 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"name": "test_for_sprite",
"version": "1.0.0",
"description": "gulp sprite",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "eyesim",
"license": "ISC",
"devDependencies": {
"gulp": "^3.9.1",
"gulp-imagemin": "^3.3.0",
"gulp-sass": "^3.1.0",
"gulp.spritesmith": "^6.5.1"
}
}

命令行: npm install

2.创建 gulpfile.js 文件

1
2
3
4
5
6
7
8
9
10
var gulp = require('gulp'),
spritesmith = require('gulp.spritesmith');

gulp.task('sprite', function() {
var spriteData = gulp.src('src/images/*.png').pipe(spritesmith({
imgName: 'sprite.png',
cssName: 'sprite.css'
}));
return spriteData.pipe(gulp.dest('static'));
});

尝试执行 gulp sprite 命令:
可以看到多了一个 static 文件夹,里面有生成的 sprite.png 与 scripte.css 文件:
static 文件夹
处理前的图片(这里面的图片均来自 iconpng.com ,如有侵犯,实属无意,可撤):
处理前的图片
处理后的 sprite 图(sprite.png):
处理后的 sprite 图
处理后的生成的 CSS 文件(sprite.css):
处理后的生成的 CSS 文件
我们可以看到,gulp.spritesmith,已经帮我们取好每一幅图的位置,也就是生产出的雪碧图不需要我们手动去调去计算位置,生产时已经一并把样式给生产了。
3.那用上 SASS ,应该怎样的呢?
我们在原基础上面增加了 cssFormat 的配置,cssFormat 有什么用呢,它的用处是指定输出样式表的格式,默认为 css,它的设置会在我们指定的文件里面以设置好的格式生产出样式。我们来试一下:

1
2
3
4
5
6
7
8
9
10
11
var gulp = require('gulp'),
spritesmith = require('gulp.spritesmith');

gulp.task('sprite', function() {
var spriteData = gulp.src('src/images/*.png').pipe(spritesmith({
imgName: 'sprite.png',
cssName: 'sprite.css',
cssFormat: 'scss'
}));
return spriteData.pipe(gulp.dest('src/static'));
});

运行一下 gulp sprite:
gulpSprite
我们来看看我们的生产的文件:
cssFomat
我们可以看到,文件名虽然是 .css 但里面的内容是 scss 的语法。
我们继续我们使用一下 SCSS,修改输出文件为 sprite.scss ,跑一遍:
scssSprite
可以看到生产出的是 SCSS 的语法代码。
我们可以在我们的项目中引入它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
//抽取部分生产出的 sprite.scss 文件的内容出来:


$mushrooms-name: 'mushrooms';
$mushrooms-x: 0px;
$mushrooms-y: 0px;
$mushrooms-offset-x: 0px;
$mushrooms-offset-y: 0px;
$mushrooms-width: 512px;
$mushrooms-height: 512px;
$mushrooms-total-width: 1024px;
$mushrooms-total-height: 1024px;
$mushrooms-image: 'sprite.png';
$mushrooms: (0px, 0px, 0px, 0px, 512px, 512px, 1024px, 1024px, 'sprite.png', 'mushrooms', );
...
$spritesheet-width: 1024px;
$spritesheet-height: 1024px;
$spritesheet-image: 'sprite.png';
$spritesheet-sprites: ($mushrooms, $pieceofcake, $skewer, $tray, );
$spritesheet: (1024px, 1024px, 'sprite.png', $spritesheet-sprites, );
...
@mixin sprite-width($sprite) {
width: nth($sprite, 5);
}

@mixin sprite-height($sprite) {
height: nth($sprite, 6);
}

@mixin sprite-position($sprite) {
$sprite-offset-x: nth($sprite, 3);
$sprite-offset-y: nth($sprite, 4);
background-position: $sprite-offset-x $sprite-offset-y;
}

@mixin sprite-image($sprite) {
$sprite-image: nth($sprite, 9);
background-image: url(#{$sprite-image});
}

@mixin sprite($sprite) {
@include sprite-image($sprite);
@include sprite-position($sprite);
@include sprite-width($sprite);
@include sprite-height($sprite);
}

// The `sprites` mixin generates identical output to the CSS template
// but can be overridden inside of SCSS
//
// @include sprites($spritesheet-sprites);
@mixin sprites($sprites) {
@each $sprite in $sprites {
$sprite-name: nth($sprite, 10);
.#{$sprite-name} {
@include sprite($sprite);
}
}
}

我们可以看到,生产出的 sprite.scss ,给我们写好了图片对应的样式,还给我们定义了相关的模块,所以我们在给元素节点添加样式时就可以这么写:

1
2
3
4
5
6
7
8
//SCSS
@import "../static/sprite.scss";

.mushroom {
@include sprite($mushrooms);
}
//HTML
<div class="mushroom"></div>

效果图

4.最后运用压缩 gulp-imagemin
在压缩前,我们先看看,图片的大小:

未生产出 sprite 前:
allPhoto
生产出的 sprite.png:
sprite.png

我们可以看到,为生产前的图片大小加起来 100KB 左右,但制作成雪碧图后,大小却比原来的要大,我们都知道,利用雪碧图可以优化 HTTP 请求,减小 HTTP 请求数量,但雪碧图有一个弊端就是,假若你的雪碧图大小过大,即使减小了请求的数量,请求时间过长也是得不偿失。
我们这里可以借用工具对雪碧图进行压缩:

1
2
3
4
5
6
7
gulp.task('sprite:minify', function() {
return gulp.src('src/static' + '/**/*.+(png|jpg|jpeg|gif|svg)')
.pipe(imagemin({
interlaced: true,
}))
.pipe(gulp.dest('src/static'))
});

minify
来看看压缩后的文件大小:

如图所见,差不多少了 40KB.

为了方便管理,最终我的 gulpfile.js 的代码是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
var gulp = require('gulp'),
spritesmith = require('gulp.spritesmith'),
imagemin = require('gulp-imagemin'),
runSequence = require('run-sequence');

var config = {
//原图片地址
spriteSource: 'src/images/',
//生产成的雪碧图存放地址
spriteSavePath: 'src/static',
spriteConfig: {
imgName: 'sprite.png',// 存放生产图片的文件名
cssName: 'sprite.scss',//存放生产图片对应的样式表,这里选用的是 SCSS
cssFormat: 'scss',//存放样式表的格式,这里写的是 scss 文件, 不填默认为 css 格式
imgPath: 'src/images',//可选选项,CSS 中引用图片的路径
padding: 0,// 表示生产出的雪碧图中图片的间隔像素,默认是 0
algorithm: 'binary-tree',//定义打包成雪碧图的打包方式,默认是 binary-tree,还有:top-down、left-right、diagonal、alt-diagonal
algorithmOpts: {
sort: true//默认是 true
},//这里的配置是针对上面的 algorithm 做配置
engine: 'pixelsmith',//对生产雪碧图图片的引擎的选用,默认选用 pixelsmith,其他的引擎例如 phantomjssmith、canvassmith、gmsmith 等需要 npm install 才可使用
engineOpts: {
// phantomjssmith 可接受超时的设置
// timeout: 10000
},//这里的配置是针对上面的 engine 做配置
imgOpts: {
// gmsmith 支持对图片质量的配置
// quality: 75
},
cssTemplate: '',//spritesmith 支持 css 模版,例如 scss.template.mustache 等,但这里的例子不打算使用
cssHandlebarsHelpers: {
// half: function (num) {
// return num/2;
// }
},//可以用于对 cssTemplate 的配置
cssVarMap: function() {

},//这是一个可以设置每个文件名到 CSS 变量的映射函数
cssSpritesheetName: '',
cssOpts: {
//例如设置跳过 mixin 的输出
//functions: false
}//这里可以对 CSS 模版的设置
},

}

//生产雪碧图
gulp.task('sprite:images', function() {
var spriteData = gulp.src( config.spriteSource + '*.+(png|jpg|jpeg|gif|svg)')
.pipe(spritesmith(config.spriteConfig));
return spriteData.pipe(gulp.dest(config.spriteSavePath));
});

//压缩
gulp.task('sprite:minify', function() {
return gulp.src(config.spriteSavePath + '/**/*.+(png|jpg|jpeg|gif|svg)')
.pipe(imagemin({
interlaced: true,
}))
.pipe(gulp.dest(config.spriteSavePath))
});

gulp.task('sprite',function() {
runSequence(
'sprite:images',
'sprite:minify'
)//使用同步插件使任务按顺序执行
});

具体代码可以参考我的 git 仓库:
https://github.com/EyesiM/gulp.Spritesmith_Try